;	BYE V6.9
;	REMOTE CONSOLE PROGRAM FOR CP/M AND MODEM
;
;---------------------------------------------------------------
; This version of BYE is contributed to CP/M-Net 'as-is'.
; It has been hacked for Australian conditions, where 
;  autodial and auto answer are illegal. The Bell-103
;  modem equates have also been removed.
; Nevertheless It shows how CDOS can be configured by BYE
;  as an RCPM host DOS.
; The table patching routines shown here effectively enable/disable
;  the printer and allow remote access to the DOS
;
; Sorry about the hacking folks..
; If you need any help contact	Trevor Marshall,
;				26 Mirrelia Way,
;				Ferndale, West Australia 6155.
;
; ps. If anyone manages to get INFOSOFT IOS to work with this pgm
; 	please let me know. I have ascertained that although IOS
;	is table driven identiaccly to CDOS (the table information
;	came from INFOSOFT) it pulls the vector addresses in during
;	initialization rather than every time a call is made and
;	although this makes it faster it will not operate with this BYE.
;	Maybe there is an undocumented system call or something???
; 14 July 1981
;-----------------------------------------------------------------
;This program allows modem callers to use your CP/M system
;just as if they were seated at the system console.  Special
;assembly-time options allow limiting the caller's access by
;password and/or access to only a message-service program.
;
;Based on an original program written by Dave Jaffe, January 1979
;Rewritten for PMMI modem by Ward Christensen, February 1979.
;The following had a hand in its development:
; Bill Precht, Hank Syzszka, P.L.Kelley, Bruce Ratoff,David Kozinn
;  ,Ron Fowler, Dave Hardy, Bruce Levison, Keith Petersen and Robbin Hough.
; before Trevor Marshall reworked it for CDOS and IOS.
;For further background information see the file 'BYE69.ASM'.
;
;------------------------------------------------
;
;This program runs up in high RAM.  It gets there
;by being moved there when 'BYE' is typed.
;
;The program in high RAM does the following:
;
;	1.	Hangs up the phone
;	2.	Awaits ring detect, allows exit
;		to CP/M if local KBD types CTL-C
;	3.	Outputs carrier (see callback routines)
;	4.	Awaits incoming carrier going to step 1
;		if none found in 15 seconds
;	5.	Asks number of nulls (0-9)
;	6.	Types the file "WELCOME" from
;		disk, allowing CTL-C to skip it
;	7.	Asks for a password, allowing
;		5 tried to get it right.
;	8.	When password entered, if used,
;		drops into CP/M.
;	9.	Caller can leave by hanging up,
;		(any time carrier is lost, it
;		waits 15 seconds, then goes
;		back to step 1), or the caller
;		may type the program name (BYE)
;
;------------------------------------------------
; The original BYE programs will not work with CDOS (IOS) because
;  they do not use the bios jump table for internal calls to I/O.
; Instead they are table driven, by an SDVT whick looks like:
; SDVT	DW	CON,TERM,RDR,PUN,LIST,CLOCK
; which in turn vectors to tables such as the console I/O
; CON	DW	CINIT,CSTAT,CINDATA,CRDY,COUTDATA
; and list
; LIST	DW	LINIT,LRDY,LOUT
;
; These tables are patched to vector to our modem BIOS.
; We can locate them by using the 81H system BDOS call
;  which returns a user register pointer in BC
; (BC) -> URREG (2)
;	  SCHSW (1)
;	  SDVT  (2)
;	  SDT	(2)
;	  SYSBOT(2)
;	  OPILINK (2)
; and so we can calculate the SDVT address.
;
; For further information (or bug info) contact
;		Trevor Marshall
;		Wait-Aid,West Aust Inst Tech,
;		Hayman Rd, Bentley, Western Australia 6102
; or ring (09) 457 6059 any time.
;
;-------------------------------------------------------
;
;
;System equates
;
FALSE	EQU	0
TRUE	EQU	NOT FALSE
;
CR	EQU	0DH
LF	EQU	0AH
MINUTES EQU	20*60		;CONSTANT FOR 1 MIN TIME DELAY
;
;Change the following equate to an area in your
;high memory where this program may patch itself in.
;Approximate memory requirements: 2k bytes or more,
;depending upon the options selected.  A marker has
;been placed at the end to deliberately print an error
;message during assembly in order to determine the actual
;ending address of the program.  The error message will
;not affect the assembly.  Make sure you have memory
;available up to the address shown.
;
DEST	EQU	0EA00H		;RUNNING LOCATION OF CODE
;
CDOS	EQU	TRUE		;If running CDOS or IOS
;
TREVORS EQU	TRUE		;True for my design
;
;
;You will likely also want to change the password,
;located below at label 'PASSWD', and the messages
;printed at label 'WELCOME' and just above label
;'HANGUP'.
;
;****************************************************
;*	    Option configuration section	    *
;****************************************************
;
PRINTER EQU	FALSE		;WANT TO RETAIN LIST DEVICE?
DUAL$IO EQU	TRUE		;WANT CONSOLE & MODEM?
CALLBAK EQU	FALSE		;WANT CALLBACK FEATURE?
PWRQD	EQU	FALSE		;WANT TO USE PASSWORD?
USRLOG	EQU	FALSE		;WANT TO COUNT NUMBER OF USERS?
HARDLOG EQU	FALSE		;WANT TO ECHO REMOTE KBD TO PRINTER?
MAXDRV	EQU	1		;HIGHEST DRIVE SUPPORTED
FASTCLK EQU	TRUE		;SET TRUE FOR 4 MHZ CLOCK
TIMEOUT EQU	FALSE		;WANT AUTO LOG-OFF FOR SLEEPY CALLERS?
TOVALUE EQU	7		;THIS IS 7 MINUTES TO AUTO LOGOUT
WELUSR	EQU	0		;USER # THAT WELCOME FILE IS KEPT IN
COMFILE EQU	TRUE		;WANT TO AUTOBOOT A COM FILE?
COMUSR	EQU	0		;USER # THAT COMFILE IS KEPT IN
DECIMAL EQU	TRUE		;WANT DECIMAL VALUES FOR LOGS?
TRAPLC	EQU	TRUE		;WANT TO TRAP LOWER CASE?
;
;Special keys for special functions
;
FKEYS	EQU	TRUE		;WANT SPECIAL FUNCTION KEYS?
;
;Assign function keys to the following control codes (if used):
;
TWITKEY EQU	'N'-40H		;KEYCODE TO LOG-OUT A CREEP
;;MSGKEY	EQU	'Q'-40H ;KEYCODE TO PRINT 'MESG FROM OPER:'
SYSDKEY EQU	'O'-40H		;KEYCODE TO PRINT SYS DOWN MSG
;
;
;****************************************************
;*	 End of option configuration section	    *
;****************************************************
;
;All modem I/O and control are here
;
;************ Trevor's modem I/O area ************
;
	IF	TREVORS
;
; USART is Intel 8251 or equivalent
;
DPORT	EQU	0F0H		;DATA PORT
CPORT	EQU	0F1H		;CONTROL PORT
SPORT	EQU	CPORT		;STATUS PORT
BPORT	EQU	0F2H		;BAUD RATE PORT
;RPORT	EQU	69H	;RING INDICATOR PORT
;
;The following are CPORT commands
;
RSTINS	EQU	42H		;RESET USART AND SEND DTR
MODINS1 EQU	4EH		;8 BITS, NO PARITY, 1 STOP BIT, 16X BAUD RATE
MODINS2 EQU	0CEH		;8 BITS, NO PARITY, 2 STOP BITS, 16X BAUD RATE
ONINS	EQU	17H		;RESET ERROR FLAGS, SEND DTR, ENABLE RECEIVE
	;AND TRANSMIT
OFFINS	EQU	10H		;DROP DTR, DISABLE RECEIVE AND TRANSMIT
;
;The following are SPORT status masks
;
TRNRDY	EQU	01H		;TRANSMITER EMPTY
RCVRDY	EQU	02H		;DATA AVAILABLE
PERR	EQU	08H		;PARITY ERROR
ORERR	EQU	10H		;OVERRUN ERROR
FRERR	EQU	20H		;FRAMING ERROR
TOERR	EQU	ORERR + FRERR	;OVERRUN PLUS FRAMING ERROR
DSR	EQU	80H		;DATA SET READY
;
;The following are baud rates for BPORT. The lower 4 bits are used
;
BD110	EQU	22H		;110 BAUD
BD300	EQU	55H		;300 BAUD
BD1200	EQU	77H		;1200 BAUD
BD2400	EQU	0AAH		;2400 BAUD
BD4800	EQU	0CCH		;4800 BAUD
BD9600	EQU	0EEH		;9600 BAUD
;
;Ring indicator port mask
;
RI	EQU	40H		;NOT RING INDICATOR (LOW TRUE)
P2RDET	EQU	RI
;
;
	ENDIF			;TREVORS
;
;---------------------------------------------------------
;
	ORG	100H
;
;Move modem interface program up to high RAM and jump to it
;but first..
; Ensure that the user is logged off if BYE is entered
;	whilst the vectors have been PATCHED
	LD	HL,(1)		;Get addr of jmp table in BIOS
	INC	HL		;see if it points beyond this addr
	LD	E,(HL)		; i.e., if it points above the BIOS
	INC	HL		; it must have been patched
	LD	D,(HL)		;addr now in DE
	LD	HL,DEST		;get address of BYE code into HL
	LD	A,L		; SUB HL,DE
	SUB	E		; HL should be > DE
	LD	L,A		; i.e., result should be >0  & <8
	LD	A,H
	SBC	D
;	MOV	H,A
	AND	80H		;if result is negative (or >32k )
	JP	NZ,GOODBY	; CDOS  is patched already
;
MOVEUP	LD	BC,PEND-START+1	;NUMBER OF BYTES TO MOVE
	LD	HL,DEST+PEND-START+1;END OF MOVED CODE
	LD	DE,SOURCE+PEND-START;END OF SOURCE CODE
;
MVLP	LD	A,(DE)		;GET BYTE
	DEC	HL		;BUMP POINTERS
	LD	(HL),A		;NEW HOME
	DEC	DE
	DEC	BC		;BUMP BYTE COUNT
	LD	A,B		;CHECK IF ZERO
	OR	C
	JP	NZ,MVLP		;IF NOT, DO SOME MORE
;
	PUSH	HL		;SAVE FOR LATER JUMP
	LD	A,0C3H		;CLEAR ANY TRAPS SO SYSOP..
	LD	(0),A		;CAN USER "BYE -A"
	XOR	A		;NEXT WARMBOOT TO USR0/DRV A
	LD	(4),A
	LD	C,14		;MAKE DRIVE A DEFAULT
	LD	E,A		;LOG-IN DRIVE CP/M FUNCTION
	CALL	BDOS
;
	RET			;TO ADRS PUSHED ABOVE
;
;
SOURCE	EQU	$		;BOUNDARY MEMORY MARKER
;
OFFSET	EQU	DEST-SOURCE	;RELOC AMOUNT
;
;-----------------------------------------------;
;	The following code gets moved		;
;	to high RAM located at "DEST",		;
;	    where it is executed.		;
;-----------------------------------------------;
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XX   C A U T I O N :  If modifying anything	XX
;XX	in this program from here on:		XX
;XX	A-L-L  labels must be of the form:	XX
;XX	LABEL	EQU	$+OFFSET		XX
;XX	in order that the relocation to high  	XX
;XX	RAM work successfully.  Forgetting to	XX
;XX	specify '$+OFFSET' will cause the pro-	XX
;XX	gram to JMP into whatever is currently	XX
;XX	in low memory, with unpredictable	XX
;XX	results.  Be careful....		XX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;
;If carrier lost, hang up, await ring.
;Otherwise, say goodbye, and hang up
;
START	EQU	$+OFFSET
;
	XOR	A		;GET 0
	LD	(LOSTFLG),A	;SHOW NO CARR. LOST
;
;Don't allow a remote user to do 'BYE -A'
;
;Check for -A option on command - request to
;go immediately into answer mode
	LD	HL,FCB+1	;TO OPTION
	LD	A,(HL)
	CP	'-'		;OPTION?
	JP	NZ,HANGUP
;Should be JMP NOSLASH??
;Got an option - validate it
	INC	HL		;TO OPTION BYTE
	LD	A,(HL)		;GET IT
	LD	(OPTION),A	;MIGHT NEED LATER
	CP	'A'		;ANSWER?
	JP	Z,ANSWER
;
;;	IF	COMFILE
;;	CPI	'C'
;;	JZ	ANSWER
;;	ENDIF		;COMFILE
;
	IF	USRLOG		;CHECK FOR RESET OF COUNTERS
	CP	'R'
	CALL	Z,RESET
	ENDIF			;USRLOG
;
	JP	HANGUP		;WE KNOW IT'S LOCAL, SO SKIP CALL TO CARCK
;
;No option, or invalid one
;
NOSLASH EQU	$+OFFSET
	CALL	CARCK		;SIGNED OFF W/THIS PROG?
	JP	C,HANGUP	;NOBODY THERE
;
GOODBY	EQU	$+OFFSET
	CALL	ILPRT		;PRINT THIS MSG:
	DEFB	CR,LF,'Cheerio, please call again'
	DEFB	CR,LF,0
	CALL	UNPATCH		;UNDO BIOS PATCHES
;
;Nobody there, or we are done, so hang up
;
HANGUP	EQU	$+OFFSET
	LD	SP,STACK	;SET UP LOCAL STACK
	XOR	A		;FORCE NEXT WARMBOOT TO USER 0
	LD	(4),A		;AND DRIVE A
	LD	C,14		;MAKE DRIVE A DEFAULT
	LD	E,A
	CALL	BDOS
	LD	A,' '		;DON'T ALLOW OPTIONS..
	LD	(OPTION),A	;..AFTER 1 "BYE / <ANYTHING>"
;
	IF	COMFILE
	CALL	LODCOM		;LOAD THE COM FILE
	ENDIF			;COMFILE
;
;
HANGUP2 EQU	$+OFFSET
;
;Clear DTR causing phone to hang up
;Was some code in here I deleted by accident;;;;;;;;;;;;;;;;
;;OFFTI	EQU	$+OFFSET
;;	CALL	DELAY	;0.1 SECOND DELAY
;;	DCR	B
;;	JNZ	OFFTI	;KEEP LOOPING UNTIL FINISHED
;;	POP	B	;RESTORE B
;;	MVI	A,ONINS	;TURN DTR ON ALLOWING MODEM TO ANSWER PHONE
;;	OUT	CPORT
;;	ENDIF		;SUPERB
;
;	IF	TREVORS	;code required
;	ENDIF	;TREVORS
;
	LD	A,0C3H		;CLEAR ANY TRAPS..
	LD	(0),A		;..LEFT FROM COM FILE
;
;Await ringing
;
RINGWT	EQU	$+OFFSET
;
;Check local keyboard for CTL-C exit request.
;NOTE: Must do input via BDOS because CBIOS patches
;are not done until call comes in.
;;	CALL	UCSTS
;;	ANI	7FH	;STRIP PARITY BIT
;;	CPI	'C'-40H ;CONTROL C?
;
;;	IF	NOT USRLOG
;;	JZ	0	;YES, --EXIT-- TO CP/M
;;	ENDIF		;NOT USRLOG
;
;;	IF	USRLOG	;PRINT OUT USER INFO
;;	JZ	PRNLOG
;;	ENDIF		;USRLOG
;
RINGW2	EQU	$+OFFSET
;;	IN	RPORT	;GET THE STATUS
;;	ANI	P2RDET	;RINGING?
;;	JNZ	RINGWT	;NO, WAIT
;
;The phone may be ringing.  Wait .1 sec and look
;again to make sure it isn't just relay bounce
;;	CALL	DELAY	;.1 SEC DELAY FOR DEBOUNCE
;;	IN	RPORT	;GET STATUS
;;	ANI	P2RDET	;STILL RINGING?
;;	JNZ	RINGWT	;NO, IT WAS RELAY BOUNCE
;
;The phone is definitely ringing, now wait until ring is finished
;
ENDRING EQU	$+OFFSET
;;	CALL	DELAY	;.1 SEC DELAY FOR DEBOUNCE
;;	IN	RPORT	;GET STATUS
;;	ANI	P2RDET	;STILL RINGING?
;;	JZ	ENDRING ;WAIT UNTIL RING FINISHED
;
	IF	CALLBAK		;NEXT ROUTINES IMPLEMENT CALLBACK
;
;This routine minimizes the computer's interference
;with normal household phone use by having computer
;folk dial, let the phone ring once, hang up and 
;then dial again.  When the phone rings only once it
;alerts the computer which then waits for and answers
;any ring which occurs within the next 40 seconds.
;
	LD	L,45		;DELAY 4.5 SECONDS FOR NEXT RING
;
WAITNX	EQU	$+OFFSET
	CALL	DELAY		;WAIT .1 SECONDS
	DEC	L		;MORE TO GO?
	JP	NZ,WAITNX	;YES, LOOP
	IN	A,RPORT		;GET THE STATUS
	AND	P2RDET		;RINGING AGAIN?
	JP	NZ,EXPECT	;NO?...ITS FOR ME!
;
;If second ring, then check for third ring, in case
;caller's phone exchange not synch'ed with computer's
;
ENDRNG2 EQU	$+OFFSET
	IN	A,RPORT		;GET THE STATUS
	AND	P2RDET		;STILL RINGING?
	JP	Z,ENDRNG2	;WAIT UNTIL RING FINISHED
	LD	L,45		;DELAY 4.5 SECONDS FOR NEXT RING
;
WAITNX2 EQU	$+OFFSET
	CALL	DELAY		;WAIT .1 SECONDS
	DEC	L		;MOE TO GO?
	JP	NZ,WAITNX2	;YES, LOOP
	IN	A,RPORT		;GET THE STATUS
	AND	P2RDET		;RINGING AGAIN?
	JP	NZ,EXPECT	;NO?...ITS FOR ME!
;
;Call not for computer - wait until ringing done, then reset
;
WAITNR	EQU	$+OFFSET
	LD	L,100		;WAIT FOR 10 SECS NO RINGING
;
WAITNRL EQU	$+OFFSET
	CALL	DELAY		;DELAY .1 SECONDS
	IN	A,RPORT		;GET THE STATUS
	AND	P2RDET		;STILL RINGING?
	JP	Z,WAITNR	;YES, WAIT 10 MORE SECONDS
	DEC	L		;NO RING, MAYBE WE'RE DONE
	JP	NZ,WAITNRL	;NO, LOOP SOME MORE
	ENDIF			;CALLBACK
;
	IF	CALLBAK AND USRLOG
	LD	A,(NONUSR)	;RECORD AS VOICE CALL
	INC	A		;ADD ONE TO COUNT
	ENDIF			;CALLBAK AND USRLOG
;
	IF	CALLBAK AND USRLOG AND DECIMAL
	DAA			;MAKE DECIMAL
	ENDIF			;CALLBK AND USRLOG AND DECIMAL
;
	IF	CALLBAK AND USRLOG
	LD	(NONUSR),A	;SAVE NEW COUNT
	ENDIF			;CALLBK AND USRLOG
;
	IF	CALLBAK		;CONTINUE WITH CALLBAK ROUTINES
	JP	HANGUP2		;GO WAIT FOR NEXT CALL
;
EXPECT	EQU	$+OFFSET
	LD	HL,400		;40 SECONDS TO WAIT FOR SECOND CALL
;
RELOOK	EQU	$+OFFSET
	IN	A,RPORT		;GET THE STATUS
	AND	P2RDET		;RINGING AGAIN?
	JP	Z,ANSWER	;YES, GO ANSWER IT
	CALL	DELAY		;WAIT .1 SECOND
	DEC	HL		;ONE LESS COUNT
	LD	A,H
	OR	L		;IS COUNT ZERO?
	JP	NZ,RELOOK	;NO, LOOK SOME MORE
	JP	HANGUP2		;COUNT DONE, WAIT FOR NEW CALL
;
	ENDIF			;END OF CALLBACK ROUTINES
;
;Setup modem
;
ANSWER	EQU	$+OFFSET
;
	IF	USRLOG		;COUNT # OF LOGON ATTEMPTS
	LD	A,(OLDUSR)	;GET # OF ATTEPMTS
	INC	A		;ADD THIS CALL
	ENDIF			;USRLOG
;
	IF	USRLOG AND DECIMAL
	DAA			;MAKE IT DECIMAL
	ENDIF			;USRLOG AND DECIMAL
;
	IF	USRLOG
	LD	(OLDUSR),A	;SAVE NEW COUNT
	ENDIF			;USRLOG
;-----------------------------------------------------
	IF	TREVORS
	LD	A,BD300		;LOAD 300 BAUD
	OUT	BPORT,A
	LD	A,2		;ensure UART points at cmd register
	OUT	CPORT,A
	CALL	UDELAY
	OUT	CPORT,A
	CALL	UDELAY
	OUT	CPORT,A
	CALL	UDELAY
	LD	A,RSTINS	;RESET USART
	OUT	CPORT,A
	CALL	UDELAY		;USART DELAY
	LD	A,MODINS2	;2 STOP BITS, ETC.
	OUT	CPORT,A
	CALL	UDELAY		;USART DELAY
	LD	A,ONINS		;DSR, ETC.
	OUT	CPORT,A
	CALL	CARCK		;SEE IF CARRIER IS PRESENT
	JP	C,HANGUP2
;Test input for baud rate
	IN	A,DPORT		;Clear any rubbish
	IN	A,DPORT
	CALL	PATCH		;PATCH JUMP TABLE
	CALL	TSTBAUD		;SEE IF 300 BAUD
	JP	Z,WELCOME	;YES, EXIT
;
	LD	A,BD1200	;LOAD 1200 BAUD
	OUT	BPORT,A
	CALL	TSTBAUD		;SEE IF 1200 BAUD
	JP	Z,WELCOME	;YES,EXIT
;
	LD	A,BD110		;LOAD 110 BAUD
	OUT	BPORT,A
	CALL	TSTBAUD		;TEST FOR 110 BAUD
	JP	Z,WELCOME
	ENDIF			;TREVORS
;
;;;	CALL	UNPATCH	
	JP	ANSWER		;TEST MORE - INVALID BAUD RATE
;
	IF	TREVORS
UDELAY	EQU	$+OFFSET
	NOP	
	NOP
	NOP
	NOP
	NOP
	NOP
	RET	
	ENDIF			;TREVORS
;
;Get the console status when unpatched
;
UCSTS	EQU	$+OFFSET
;
	LD	C,CSTS		;IN CPM 1.4, WE HAVE TO GET..
	CALL	BDOS		;..THE STATUS FIRST
	OR	A
	RET	Z
	LD	C,CI		;AND THEN THE CHARACTER
	CALL	BDOS
	RET	
;
;Following are the USRLOG routines
;
	IF	USRLOG		;INCLUDE RESET FUNCTIONS
RESET	EQU	$+OFFSET	;RESET ALL LOGON COUNTERS
	XOR	A
	ENDIF			;USRLOG
;
	IF	USRLOG AND PWRQD
	LD	(OLDUSR),A	;RESET ATTEMPT COUNTER
	ENDIF			;USRLOG AND PWRQD
;
	IF	USRLOG
	LD	(NEWUSR),A	;RESET LOGON COUNTER
	ENDIF			;USRLOG
;
	IF	USRLOG AND CALLBAK
	LD	(NONUSR),A	;RESET VOICE COUNTER
	ENDIF			;USRLOG AND CALLBAK
;
	IF	USRLOG
	RET	
	ENDIF			;USRLOG
;
PRNLOG	EQU	$+OFFSET
;
	IF	USRLOG AND PWRQD;PRINT # OF LOGON ATTEMPTS
	LD	C,PRINTF
	LD	DE,ATMSG
	CALL	BDOS
	LD	A,(OLDUSR)
	CALL	HXOUT
	ENDIF			;USRLOG AND PWRQD
;
	IF	USRLOG		;PRINT # OF LOGONS
	LD	C,PRINTF
	LD	DE,SUMSG
	CALL	BDOS
	LD	A,(NEWUSR)
	CALL	HXOUT
	ENDIF			;USRLOG
;
	IF	USRLOG AND CALLBAK;# OF VOICE CALLS
	LD	C,PRINTF
	LD	DE,VCMSG
	CALL	BDOS
	LD	A,(NONUSR)
	CALL	HXOUT
	ENDIF			;USRLOG AND CALLBAK
;
	IF	USRLOG
	JP	0		;WARM-BOOT BACK TO CP/M
	ENDIF			;USRLOG
;
	IF	USRLOG AND PWRQD
ATMSG	EQU	$+OFFSET
	DEFB	LF,CR,'NUMBER OF LOGON ATTEMPTS: $'
	ENDIF			;USRLOG AND PWRQD
;
	IF	USRLOG
SUMSG	EQU	$+OFFSET
	DEFB	LF,CR,'NUMBER OF LOGONS: $'
	ENDIF			;USRLOG
;
	IF	USRLOG AND CALLBAK
VCMSG	EQU	$+OFFSET
	DEFB	LF,CR,'NUMBER OF VOICE CALLS: $'
	ENDIF			;USRLOG AND CALLBAK
;
	IF	USRLOG
HXOUT	EQU	$+OFFSET
	LD	B,A		;SAVE NUMBER
	RRA			;ROTATE RIGHT 4 BITS
	RRA			;TO MAKE AN ASCII DIGIT
	RRA	
	RRA	
	CALL	ONEOUT		;OUTPUT MSH TO CONSOLE
	LD	A,B		;GET NUMBER BACK
;
ONEOUT	EQU	$+OFFSET
	AND	0FH		;GET LSH FOR OUTPUT
	CP	0AH		;CHECK IF ALPHA
	JP	C,NOTAL2
	ADD	07H
;
NOTAL2	EQU	$+OFFSET
	ADD	30H
	PUSH	BC
	LD	C,02H
	LD	E,A		;OUTPUT THE NUMBER
	CALL	BDOS
	POP	BC
	RET	
	ENDIF			;USRLOG
;
;Welcome to the system
;
WELCOME EQU	$+OFFSET
;
GETNULL EQU	$+OFFSET
	CALL	ILPRT		;PRINT THIS MSG:
	DEFB	CR,LF
	DEFB	'HOW MANY NULLS (0-9) DO YOU NEED? ',0
	CALL	MINPUT		;GET VALUE
;;;	MOV	C,A	;TO C FOR MOUTPUT
	CALL	MOUTPUT		;ECHO CHAR
;;;	MOV	A,C	;RESTORE VALUE
	CP	'0'
	JP	C,GETNULL	;BAD, RETRY
	CP	'9'+1
	JP	NC,GETNULL	;BAD
	SUB	'0'		;MAKE BINARY
	LD	(NULLS),A	;SAVE COUNT
;
	IF	TRAPLC
GETULC	EQU	$+OFFSET
	CALL	ILPRT		;PRINT THIS MSG:
	DEFB	CR,LF
	DEFB	'CAN YOUR TERMINAL DISPLAY LOWER CASE? ',0
	LD	A,20H		;FORCE CASE CONVERSION FOR NOW
	LD	(ULCSW),A
	CALL	MINPUT		;GET Y OR NO
;;;	MOV	C,A
	CALL	MOUTPUT		;ECHO
;;;	MOV	A,C
	CP	'N'
	JP	Z,DONEOPT	;WE'RE ALREADY SET UP FOR NO LWR CASE
	CP	'Y'
	JP	NZ,GETULC	;WASN'T Y OR N...GO ASK AGAIN
	XOR	A
	LD	(ULCSW),A	;SET FLAG FOR NO CONVERSION
;
DONEOPT EQU	$+OFFSET
	ENDIF			;TRAPLC
;
	CALL	ILPRT
	DEFB	CR,LF,0
;Print the welcome file
	LD	HL,WELFILN	;SOURCE
	LD	DE,FCB		;DESTINATION
	LD	B,13		;LENGTH
	CALL	MOVE		;MOVE THE NAME
;Set DMA address to 80h
	LD	DE,80H
	LD	C,STDMA
	CALL	BDOS
;
;Open the welcome file
	LD	DE,FCB
	LD	C,OPEN
	CALL	BDOS
;Did it exist?
	INC	A		;A=> 0 MEANS "NO"
	JP	Z,PASSINT	;NO WELCOME FILE
;Got a file, type it
	XOR	A		;GET 0
	LD	(FCBRNO),A	;ZERO RECORD #
	LD	HL,100H		;GET INITIAL BUFF POINTER
;
;Type the welcome file
WELTYLP EQU	$+OFFSET
	CALL	RDBYTE		;GET A BYTE
	CP	1AH		;EOF?
	JP	Z,PASSINT	;YES, DONE
;;;	MOV	C,A	;SETUP FOR TYPE
	CALL	MOUTPUT		;TYPE THE CHAR
	CALL	MSTAT		;CHECK FOR..
	OR	A		;CHAR TYPED?
	JP	Z,WELTYLP	;..NO, LOOP
	CALL	MINPUT		;..YES, GET CHAR
	CP	'C'-40H		;CTL-C?
	JP	NZ,WELTYLP	;..NO, LOOP UNTIL EOF
;
;Get the password
;
PASSINT EQU	$+OFFSET
;
	IF	PWRQD
	LD	D,5		;5 TRIES AT PASSWORD
;
PASSINP EQU	$+OFFSET
	CALL	ILPRT
	DEFB	CR,LF,'ENTER PASSWORD: ',0
	LD	HL,PASSWD	;POINT TO PASSWORD
	LD	E,0		;NO MISSED LETTERS
	IN	A,DPORT		;CLEAR OUT GARBAGE
;
PWMLP	EQU	$+OFFSET
	CALL	MINPUT		;GET A CHAR
	CP	'U'-40H		;CTL-U?
	JP	Z,PASSINP	;YES, RE-GET IT
	CP	60H		;LOWER CASE?
	JP	C,NOTLC		;NO,
	AND	5FH		;MAKE UPPER CASE ALPHA
;
NOTLC	EQU	$+OFFSET
	CP	(HL)		;MATCH PASSWORD?
	JP	Z,PWMAT		;..YES
	LD	E,1		;..NO, SHOW MISS
	CP	CR		;C/R?
	JP	NZ,PWMLP	;..NO, WAIT FOR C/R
;
;Password didn't match
;
PWNMAT	EQU	$+OFFSET
	CALL	ILPRT
	DEFB	'++INCORRECT++',CR,LF,0
	DEC	D		;MORE TRIES?
	JP	NZ,PASSINP	;YES
	JP	BADPASS		;NO, GO HANG UP
;
;Character matched in password
;
PWMAT	EQU	$+OFFSET
	INC	HL		;TO NEXT CHAR
	CP	CR		;END?
	JP	NZ,PWMLP	;..NO, LOOP
;End of password.  Any missed chars?
	LD	A,E		;GET FLAG
	OR	A
	JP	NZ,PWNMAT	;NOT RIGHT
;Password correct
	ENDIF			;PWRQD
;
NOPASS	EQU	$+OFFSET
;
	IF	USRLOG		;COUNT # OF SUCCESSFUL LOGONS
	LD	A,(NEWUSR)	;GET LAST VALUE
	INC	A		;INCREMENT IT
	ENDIF			;USRLOG
;
	IF	USRLOG AND DECIMAL
	DAA			;MAKE IT DECIMAL
	ENDIF			;USRLOG AND DECIMAL
;
	IF	USRLOG
	LD	(NEWUSR),A	;SAVE NEW VALUE
	ENDIF			;USRLOG
;
;;	CALL	ILPRT
;;	DB	CR,LF,'Booting CDOS.. ',0DH,0AH,0	;PUT BOOT-UP MSG HERE
;
	IF	COMFILE
	LD	A,(OPTION)
	CP	'A'		;SYSOP CAN BYPASS COM FILE BY..
	JP	Z,0		;..TYPING "BYE /A"
;;	CPI	'C'	;OPER CAN ALSO GO TO COM..
;;	JNZ	100H	;..FILE LOAD WITH "BYE /C"
;;	CALL	ILPRT	;PRINT THIS MESSAGE:'
;;	DB	'Loading system...',CR,LF,0
;;	CALL	LODCOM
	LD	A,'@'		;Tell RBBS that this is a
	LD	(5DH),A		; new caller
	JP	100H		;EVERYONE ELSE GETS COM FILE
	ENDIF			;COMFILE
;
	IF	NOT COMFILE
	JP	0
	ENDIF			;NOT COMFILE
;
;TSTBAUD attempts to read a LF or CR, returns with
;zero flag if the character read is one of these two.
;
TSTBAUD EQU	$+OFFSET
	CALL	MINPUT		;GET CHARACTER FROM MODEM
	CP	CR		;IF A CARRIAGE RETURN...
	RET	Z		;.. RETURN
	CP	LF		;IF A LINEFEED...
	RET			;RET ZERO FLAG, ELSE NOT ZERO
;
;Loss of connection test
;
CARCK	EQU	$+OFFSET
;
;;;	IF	SUPERB
;
;Racal-Vadic modem automatically hangs up phone 1 second
;after carrier loss.
;
;;;	IN	SPORT	;GET STATUS
;;;	ANI	DSR	;CHECK IF CARRIER ON
;;;	JNZ	CARCK2	;YES, CONTINUE ON
;;;	STC		;SET CARRY BIT FOR NO CARRIER
;;;	RET
;;;	ENDIF		;SUPERB
;
	IF	TREVORS
;
;;	IN	SPORT	;GET STATUS
;;	ANI	DSR	;CHECK IF CARRIER ON
;;	JNZ	CARCK2	;YES, CONTINUE ON
;******************always have carrier
;;	STC		;SET CARRY BIT FOR NO CARRIER
;;	RET
	ENDIF			;TREVORS
;
;Now test drive #'s and (if CP/M 2.x) user #'s to
;insure that maximums are not exceeded.
;
CARCK2	EQU	$+OFFSET
	LD	A,(4)		;CHECK DISK/USER #
	AND	0FH		;ISOLATE DRIVE
	CP	MAXDRV		;VALID DRIVE?
	JP	C,CARCK3	;YES, SKIP THIS JUNK
	LD	A,(4)		;GET WHOLE LOGIN BYTE
	AND	0F0H		;RETAIN USER # & FORCE DRIVE TO A
	LD	(4),A		;UPDATE LOGIN BYTE
	CALL	ILPRT		;TELL USER WHAT HE DID
	DEFB	'Invalid drive - returning to A:',0
	JP	0		;WARM BOOT
;
CARCK3	EQU	$+OFFSET
;
CARCK4	EQU	$+OFFSET
	OR	A
	RET	
;
;.1 sec delay routine
;
DELAY	EQU	$+OFFSET
;;	PUSH	B
;
;;	IF	FASTCLK
;;	LXI	B,16667 ;4 MHZ TIMING CONSTANT
;;	ENDIF
;
;;	IF	NOT FASTCLK
;;	LXI	B,8334	;2 MHZ TIMING CONSTANT
;;	ENDIF
;
;;DELAY1	EQU	$+OFFSET
;;	DCX	B
;;	MOV	A,B
;;	ORA	C
;;	JNZ	DELAY1
;;	POP	B
;;	RET
;
;50 ms delay routine
;
;;KDELAY	EQU	$+OFFSET
;;	PUSH	B
;
;;	IF	FASTCLK
;;	LXI	B,8334
;;	ENDIF
;
;;	IF	NOT FASTCLK
;;	LXI	B,4167
;;	ENDIF
;
;;	JMP	DELAY1
;
;Patch in the new JMP table (saving the old)
;
PATCH	EQU	$+OFFSET
	CALL	TBLADDR		;CALC HL= CP/M JMP TABLE
	LD	DE,VCOLDBT	;POINT TO SAVE LOCATION
	LD	B,18		;ALWAYS SAVE PRINTER VECTOR
	CALL	MOVE		;MOVE IT
;Now move new JMP table to CP/M
	CALL	TBLADDR		;CALC HL=CP/M'S JMP TABLE
	EX	DE,HL		;MOVE TO DE
	LD	HL,NEWJTBL	;POINT TO NEW
	CALL	MOVE		;MOVE IT
;
	IF	CDOS		;we must copy and replace SDVT console entries
;
	LD	C,81H
	CALL	BDOS		;Get user register pointer
	LD	HL,3
	ADD	HL,BC		;HL now pointing to SDVT entry
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		;Have SDVT vector in DE
	EX	DE,HL		;in HL
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		;Have CON$TABLE in DE
	EX	DE,HL		;in HL
	LD	(CON$TABLE),HL	;save it in RAM
	LD	DE,DOSSDVT	;where we will save it
	LD	B,10		;10 bytes to move
	CALL	MOVE		;(hl) to (de)
;
	LD	HL,(CON$TABLE)	;Now overlay with our SDVT
	EX	DE,HL
	LD	HL,SDVT		;our SDVT points to modem routines
	LD	B,10
	CALL	MOVE
;
; Now patch the vectors into our CONIN etc
	LD	HL,(DOSCSTAT)
	LD	(CSTAT),HL
	LD	HL,(DOSCIND)
	LD	(CIND),HL
	LD	HL,(DOSCOUTD)
	LD	(COUTD),HL
	IF	NOT PRINTER
; Now replace printer table LINIT and LOUT entry
	LD	C,81H
	CALL	BDOS		;Get user register pointer
	LD	HL,3		;calculate the  SDVT entry
	ADD	HL,BC
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		;Have SDVT table addr in DE
	LD	HL,8		;get LIST table  addr
	ADD	HL,DE
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		;DE points at LIST table
	INC	DE
	INC	DE
	EX	DE,HL
	LD	(LRDY$ADDR),HL	;where we will save it
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		;Have original LRDY vector in DE
	EX	DE,HL		;inHL
	LD	(SAVE$LRDY),HL
	EX	DE,HL		;get back table ptr
	INC	HL
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		;have LOUT vec in DE
	EX	DE,HL
	LD	(SAVE$LOUT),HL
	CALL	DISABLE$PRINTER
	ENDIF			;NOT PRINTER
	ENDIF			;CDOS
	RET	
;
;Now replace the vectors if required
	IF	NOT PRINTER	;we will patch out table entries
DISABLE$PRINTER EQU	$+OFFSET
	LD	HL,(LRDY$ADDR)
	LD	DE,MSTAT1	;Replace vector
	LD	(HL),E
	INC	HL
	LD	(HL),D
;
	INC	HL		;now replace LOUT
	LD	DE,DUMMY	;merely RETurn
	LD	(HL),E
	INC	HL
	LD	(HL),D
	RET	
;
ENABLE$PRINTER EQU	$+OFFSET
;Now return the vectors if required
	LD	HL,(SAVE$LRDY)	;get original vector
	EX	DE,HL		;into DE
	LD	HL,(LRDY$ADDR)
	LD	(HL),E
	INC	HL
	LD	(HL),D
;
	INC	HL		;now replace LOUT
	PUSH	HL
	LD	HL,(SAVE$LOUT)
	EX	DE,HL
	POP	HL
	LD	(HL),E
	INC	HL
	LD	(HL),D
	RET	
	ENDIF			;NOT PRINTER
UNPATCH EQU	$+OFFSET
	CALL	TBLADDR		;HL=CP/M'S JMP TABLE
	EX	DE,HL		;MOVE TO DE
	LD	HL,VCOLDBT	;GET SAVED TABLE
	CALL	MOVE		;MOVE ORIG BACK
;
	IF	CDOS		;must also move SDVT back
	LD	HL,(CON$TABLE)
	EX	DE,HL		;DE now holds addr of CDOS's SDVT
	LD	HL,DOSSDVT	;HL has the saved SDVT addr
	LD	B,10		;length of SDVT
	CALL	MOVE		;restore old SDVT
	IF	NOT PRINTER
	CALL	ENABLE$PRINTER
	ENDIF			;NOT PRINTER
	ENDIF			;CDOS
	RET	
;
;Calculate HL=CP/M's jump table, B=length
;
TBLADDR EQU	$+OFFSET
	LD	HL,(1)		;GET BIOS POINTER
	DEC	HL		;..SKIP
	DEC	HL		;..TO
	DEC	HL		;..COLD BOOT
;
	IF	NOT CDOS
	IF	NOT PRINTER
	LD	B,18		;BYTES TO MOVE
	ENDIF	
;
	IF	PRINTER		;RETAIN LIST DEVICE?
	LD	B,15		;DON'T MOVE LISTER JUMP
	ENDIF	
;
	ENDIF			;NOT CDOS
	IF	CDOS
	LD	B,6		;only copy the two boot vectors
	ENDIF			;CDOS
	RET	
;
;Move (HL) to (DE), length in (B)
;
MOVE	EQU	$+OFFSET
	LD	A,(HL)		;GET A BYTE
	LD	(DE),A		;PUT AT NEW HOME
	INC	DE		;BUMP POINTERS
	INC	HL
	DEC	B		;DEC BYTE COUNT
	JP	NZ,MOVE		;IF MORE, DO IT
	RET			;IF NOT,RETURN
;
;Common routine to check for carrier lost, called from console out
;
CHECK	EQU	$+OFFSET
	CALL	CARCK		;SEE IF CARRIER STILL ON
	RET	NC		;ALL OK
;
;Carrier is lost.  Type message so local console shows the reason
;
BADPASS EQU	$+OFFSET	;COME HERE ON BAD PASSWORD
	LD	A,1		;SHOW CARRIER LOST SO
	LD	(LOSTFLG),A	;..WE WON'T CK AGAIN
	LD	SP,STACK	;ENSURE VALID STACK
	CALL	ILPRT
	DEFB	CR,LF
	DEFB	'++CARRIER LOST++'
	DEFB	CR,LF,'   ',0
	CALL	UNPATCH		;RESTORE ORIG BIOS JMP TBL
	XOR	A		;CLEAR OUT CARRIER..
	LD	(LOSTFLG),A	;..LOST FLAG
	JP	HANGUP
;
;Readbyte routine - used to read the welcome file
;
RDBYTE	EQU	$+OFFSET
	LD	A,H		;TIME TO READ?
	OR	A		;..IF AT 100H
	JP	Z,NORD		;NO READ REQ'D
;Have to read a sector
	LD	DE,FCB
	LD	C,READ
	CALL	BDOS
	OR	A		;OK?
	LD	A,1AH		;FAKE UP EOF
	RET	NZ		;RET EOF IF BAD
	LD	HL,80H
;
NORD	EQU	$+OFFSET
	LD	A,(HL)		;GET CHAR
	INC	HL		;TO NEXT
	RET	
;
;Keyboard/modem status test routine
;
MSTAT	EQU	$+OFFSET
;
	IF	DUAL$IO		;WANT LOCAL CONSOLE?
	CALL	CONSTAT		;GET LOCAL STATUS
	OR	A
	RET	NZ		;RET IF LOCAL CHAR
	ENDIF			;DUAL$IO
;
	IF	TREVORS
	IN	A,SPORT		;GET STATUS
	AND	RCVRDY		;GOT A CHARACTER
	RET	Z		;RETURN IF NOT
;;	IN	SPORT	;GET STATUS
;;	ANI	TOERR	;CHECK FOR FRAMING AND OVERRUN ERRORS
;;	JZ	MSTAT1	;NO ERRORS
;;	MVI	A,ONINS	;RESET ERROR FLAGS
;;	OUT	CPORT
;;	XRA	A	;RETURN	FALSE
;;	RET
	ENDIF			;TREVORS
;
MSTAT1	EQU	$+OFFSET
	LD	A,0FFH		;SHOW READY
	OR	A
	RET	
;
;Modem input function, checks local console first
;
MINPUT	EQU	$+OFFSET
;
	IF	TIMEOUT
	PUSH	HL
	LD	HL,TOVALUE*MINUTES;INITIALIZE TIMEOUT COUNTER
	LD	(TOCNT),HL
	POP	HL
	ENDIF			;TIMEOUT
;
MINPUT1 EQU	$+OFFSET
	LD	A,(LOSTFLG)	;KNOWN LOSS..
	OR	A		;..OF CARRIER?
	CALL	Z,CHECK		;CARRIER STILL ON?
	CALL	MSTAT		;ANYTHING?
	OR	A
;
	IF	NOT TIMEOUT
	JP	Z,MINPUT	;LOOP TILL CHAR RCD
	ENDIF			;NOT TIMEOUT
;
	IF	TIMEOUT
	JP	NZ,MINPUT2
	CALL	KDELAY		;KILL 50 MS
	PUSH	HL
	LD	HL,(TOCNT)	;KNOCK DOWN TIMEOUT COUNTER
	DEC	HL
	LD	(TOCNT),HL
	LD	A,H
	OR	L
	POP	HL
	JP	NZ,MINPUT1	;STILL TIME LEFT..KEEP TRYING
	CALL	ILPRT
	DEFB	'++INPUT TIMED OUT++',7,7,0
	JP	NOSLASH
	ENDIF			;TIMEOUT
;
MINPUT2 EQU	$+OFFSET
;
	IF	DUAL$IO		;BOTH LOCAL AND REMOTE
	CALL	CONSTAT		;CHECK LOCAL CONSOLE
	OR	A		;CHAR?
	JP	NZ,CONIN	;..YES, READ IT, RET.
	ENDIF	
;
;Local console wasn't ready, so read modem
;
	IN	A,DPORT		;GET DATA BYTE
	AND	7FH		;DELETE PARITY
	JP	Z,MINPUT	;IGNORE NULLS
;
	IF	HARDLOG
	CP	20H
	JP	NC,MINPUT3
	CP	CR
	JP	NZ,NOLOG
;
MINPUT3 EQU	$+OFFSET
	CALL	LISTOUT		;ECHO ON PRINTER
	CP	CR
	JP	NZ,NOLOG	;CR NEEDS LINEFEED
	LD	A,LF
	CALL	LISTOUT		;SO SEND IT
	LD	A,CR		;GET BACK CR
	ENDIF			;END OF HARDLOG
;
NOLOG	EQU	$+OFFSET
;
	CP	3		;IS IT CONTROL-C?
	RET	NZ		;NO, PASS IT THRU
	LD	A,(0)		;SEE IF WARM BOOT DISABLED
	CP	0C3H		;JMP MEANS WARM BOOT OK
	LD	A,3		;SO RETURN CONTROL-C
	RET	Z
	XOR	A		;ELSE CONVERT TO NULL
	RET	
;
;Modem output function
;
MOUTPUT EQU	$+OFFSET
	LD	C,A		;char is passed in A for CDOS
CMOUTPUT EQU	$+OFFSET	;CP/M passes it in C
;
;If we already know carrier is lost, don't check
;for it again or loop trying to output.
	LD	A,(LOSTFLG)	;KNOWN LOSS OF CARRIER?
	OR	A
	JP	NZ,SILENT	;AVOID LOOP IN CASE CARRIER LOST
	CALL	CHECK		;CARRIER STILL ON?
;
	IF	TREVORS
	IN	A,SPORT		;GET MODEM STATUS
	AND	TRNRDY		;TRANSMIT BUFFER EMPTY?
	ENDIF			;TREVORS
;
	JP	Z,CMOUTPUT	;LOOP IF NOT READY
;
	LD	A,C		;GET CHAR
	AND	7FH		;STRIP PARITY BIT
;
	IF	TRAPLC
	CP	60H		;CHECK FOR LOWER CASE
	JP	C,MOUTP2	;SKIP IF NOT LC
	CP	7FH		;CHECK FOR RUBOUT
	JP	Z,MOUTP2
	PUSH	HL
	LD	HL,ULCSW	;SUBTRACT EITHER 20H OR 0
	SUB	(HL)
	POP	HL
	LD	C,A		;FORCE ON LOCAL AS WELL AS REMOTE
;
MOUTP2	EQU	$+OFFSET
	ENDIF			;TRAPLC
;
	OUT	DPORT,A		;OUTPUT TO MODEM
;
SILENT	EQU	$+OFFSET
;
	IF	DUAL$IO		;TO LOCAL ALSO?
	LD	A,C		;for CDOS
	PUSH	AF		;SAVE CHAR
	CALL	CONOUT		;SEND TO REGULAR BIOS char in A or C
	POP	AF		;GET CHAR AGAIN
	ENDIF			;DUAL$IO
;
;Check for nulls
	CP	LF		;TIME FOR NULLS?
	RET	NZ		;NO, RETURN
;Send nulls if required
	LD	A,(NULLS)	;GET COUNT
	OR	A		;ANY?
	RET	Z		;..NO
	PUSH	BC
	LD	B,A		;SAVE COUNT
	LD	A,0		;0 IS A NULL
;
NULLP	EQU	$+OFFSET
	CALL	MOUTPUT		;TYPE A NULL
	DEC	B		;MORE?
	JP	NZ,NULLP	;..YES, LOOP
	POP	BC
	LD	C,LF		;RESTORE LF
	RET	
;
;Boot trap - becomes disconnect if JMP at 0 has been altered
;
MBOOT	EQU	$+OFFSET
;;	LDA	0	;LOOK AT OPCODE
;;	CPI	0C3H	;IS IT STILL JMP?
;;	JZ	VWARMBT ;YES, ALLOW IT
;;	JMP	NOSLASH ;NO, DISCONNECT
	JP	VWARMBT		;++++++++++++++;;;;;;;;;;;;;;;;;;;;;;;;
;
;Inline print routine
;
ILPRT	EQU	$+OFFSET
	EX	(SP),HL		;SAVE HL, GET MSG
	PUSH	BC		;SAVE BC REGS
;
ILPLP	EQU	$+OFFSET
	LD	C,(HL)		;GET CHAR
	CALL	CMOUTPUT	;OUTPUT IT
	INC	HL		;POINT TO NEXT
	LD	A,(HL)		;TEST
	OR	A		;..FOR END
	JP	NZ,ILPLP
	POP	BC		;RESTORE BC REGS
	EX	(SP),HL		;RESTORE HL, RET ADDR
	RET			;RET PAST MSG
;
	IF	PWRQD		;KEEP PASSWORD HERE
;Access password (ends in carriage return)
;
PASSWD	EQU	$+OFFSET
	DEFB	'HELLO'		;THE PASSWORD ITSELF
	DEFB	CR		;END OF PASSWORD
;Allow room for bigger password to be patched in
	DEFB	0,0,0,0,0,0,0,0,0,0,0,0,0
	ENDIF			;PWRQD
;
;Routine to load the COM file
;
	IF	COMFILE
LODCOM	EQU	$+OFFSET
	XOR	A		;INITIALIZE FCB
	LD	(COMFCB),A
	LD	HL,COMFCB+12
	LD	B,21
;
ZLOOP	EQU	$+OFFSET
	LD	(HL),0
	INC	HL
	DEC	B
	JP	NZ,ZLOOP
;
	LD	C,OPEN		;NOW OPEN THE FILE
	LD	DE,COMFCB
	CALL	BDOS
	INC	A		;SHOULD BE NON-ZERO
	JP	Z,ABORT		;NO FILE, ABORT
;
;Now load the file
	LD	HL,(6)		;GET TOP OF MEMORY
	LD	DE,-80H		;RECORD LOADS CAN'T START..
	ADD	HL,DE		;..ABOVE (BDOS) - 80H
	PUSH	HL		;SAVE ON STACK
;
	LD	DE,80H		;TPA-80H
	LD	BC,0		;KEEP A RECORD COUNTER
	PUSH	BC		;SAVE COUNTER
	PUSH	DE		;AND LOAD ADDRESS
;
GLOOP	EQU	$+OFFSET
	POP	DE		;GET TPA ADRS
	LD	HL,80H		;POINT TO NXT ADRS TO READ TO
	ADD	HL,DE		;HL HAS THE ADDRESS
	POP	BC		;INCREMENT THE COUNTER
;Check for load past top-of-memory
	POP	DE		;GET (TOP-OF-MEMORY)
	PUSH	DE		;RE-SAVE FOR NEXT TIME
	LD	A,E		;SUBTRACT: (TOP) - (ADRS)
	SUB	L
	LD	A,D		;ONLY THE CARRY NEEDED
	SBC	H
	JP	NC,SIZEOK	;CY= BETTER MOVCPM
	CALL	ERRXIT		;SO TELL THE STORY
	DEFB	'Out of memory','$'
;
SIZEOK	EQU	$+OFFSET
	INC	BC
	PUSH	BC
	PUSH	HL		;SAVE TPA ADRS
	EX	DE,HL		;ALIGN REGISTERS
	LD	C,STDMA		;TELL BDOS WHERE TO PUT RECORD
	CALL	BDOS
	LD	DE,COMFCB	;NOW READ THE RECORD
	LD	C,READ
	CALL	BDOS
	OR	A
	JP	Z,GLOOP		;A=0 IF MORE TO READ
	POP	BC		;UNJUNK STACK
	POP	BC		;THIS IS OUR COUNTER
	POP	HL		;MORE JUNK ON STACK
	LD	A,B		;CHECK FOR ZERO
	OR	C
	JP	Z,ABORT		;WE SHOULD HAVE READ SOMETHING
	LD	DE,80H		;WE DID, RESET DMA TO 80H
	LD	C,STDMA
	CALL	BDOS
	CALL	LOADOK		;PRINT THIS MSG TO CONSOLE:
	DEFB	'RBBS loaded',CR,LF,'$'
;
LOADOK	EQU	$+OFFSET
	POP	DE
	LD	A,(OPTION)	;SEE IF THIS WAS "BYE /C"
	CP	'C'		;IF IT WAS THEN..
	RET	Z		;..DON'T PRINT MESSAGE
	LD	C,PRINTF
	CALL	BDOS
	RET	
;
ABORT	EQU	$+OFFSET
	CALL	ERRXIT
	DEFB	CR,LF
	DEFB	'Open err','$'
;
ERRXIT	EQU	$+OFFSET
	POP	DE
	LD	C,PRINTF
	CALL	BDOS		;PRINT THE ABORT MSG
	JP	0		;WARM BOOT
	ENDIF			;COMFILE
;
;This area is used for vectoring calls to the
;user's CBIOS, but saving the registers first
;in case they are destroyed.
;
CONSTAT EQU	$+OFFSET
	PUSH	BC
	PUSH	DE
	PUSH	HL
CSTAT	EQU	$+1+OFFSET
	CALL	VCONSTAT
	POP	HL
	POP	DE
	POP	BC
	RET	
;
CONIN	EQU	$+OFFSET
	PUSH	BC
	PUSH	DE
	PUSH	HL
CIND	EQU	$+1+OFFSET
	CALL	VCONIN
;
	IF	FKEYS
	CALL	CKFUNC
	ENDIF			;FKEYS
;
	POP	HL
	POP	DE
	POP	BC
	RET	
;
CKFUNC	EQU	$+OFFSET
;
	IF	FKEYS
	CP	SYSDKEY
	JP	Z,SYSDOWN	;TELL CALLER TO LEAVE
	CP	TWITKEY
	JP	Z,GOODBY	;MAKE CALLER LEAVE
;;	CP	MSGKEY
;;	RET	NZ
;;	CALL	ILPRT		;SEND CALLER A MESSAGE
;;	DEFB	'MESSAGE FROM OPERATOR:',0
;;	LD	A,' '		;SOMETHING TO RETURN WITH
	RET	
;
SYSDOWN EQU	$+OFFSET
	CALL	ILPRT
	DEFB	'SYSTEM DOWN IN'
	DEFB	' 5 MINUTES....',0
	LD	A,' '
	RET	
	ENDIF			;FKEYS
;
CONOUT	EQU	$+OFFSET
	PUSH	BC
	PUSH	DE
	PUSH	HL
;	MOV	A,C	;Get char in A for CDOS
	PUSH	AF
COUTD	EQU	$+1+OFFSET
	CALL	VCONOUT
	POP	AF
	POP	HL
	POP	DE
	POP	BC
	RET	
;
LISTOUT EQU	$+OFFSET
	PUSH	BC
	PUSH	DE
	PUSH	HL
	PUSH	AF
	IF	NOT PRINTER
	CALL	ENABLE$PRINTER
	ENDIF			;NOT PRINTER
	POP	AF
	PUSH	AF
	LD	A,C		;char needed in A
LOUT	EQU	$+1+OFFSET
	CALL	VLISTOUT
	IF	NOT PRINTER
	CALL	DISABLE$PRINTER
	ENDIF			;NOT PRINTER
	POP	AF
	POP	HL
	POP	DE
	POP	BC
MINIT	EQU	$+OFFSET	;merely a return opcode
	RET	
;
;This is the JMP table which is copied on top
;of the one pointed to by location 1 in CP/M
;If CDOS is in use only the first 2 vectors are replaced
NEWJTBL EQU	$+OFFSET
	JP	MBOOT		;COLD BOOT
	JP	MBOOT		;WARM BOOT
	JP	MSTAT		;MODEM STATUS TEST
	JP	MINPUT		;MODEM INPUT ROUTINE
	JP	CMOUTPUT	;MODEM OUTPUT ROUTINE
DUMMY	EQU	$+OFFSET
	RET			;DUMMY LIST DEVICE
	NOP	
	NOP	
;
WELFILN EQU	$+OFFSET
	DEFB	0,'WELCOME    ',0
;Welcome file name ^^^^^^^^^^^ (must be 11 characters)
;
NULLS	EQU	$+OFFSET
	DEFB	5
;
COMFCB	EQU	$+OFFSET
	DEFB	0,'RBBS    COM'
;COM file name	   ^^^^^^^^^^^ (must be 11 characters)
;
	IF	NOT CDOS
PEND	EQU	$+OFFSET	;END OF RELOCATED CODE
	ENDIF			;NOT CDOS
;
;These areas are not initialized for CP/M only
;
	DEFS	21		;REST OF COM FCB
;
	IF	CDOS
; This is the SDVT table which is copied on top
;  of the one in CDOS or IOS
SDVT	EQU	$+OFFSET	;10 BYTES LONG
	DEFW	MINIT		;returns OK immediately
	DEFW	MSTAT
	DEFW	MINPUT
	DEFW	MSTAT1		;wants status,gets READY
	DEFW	MOUTPUT
;
PEND	EQU	$+OFFSET	;END OF RELOCATED CODE
;
	DEFS	2		;to allow for movement errors
CON$TABLE EQU	$+OFFSET
	DEFS	2		;Store DOSSDVT addr here
LRDY$ADDR EQU	$+OFFSET
	DEFS	2
SAVE$LRDY EQU	$+OFFSET
	DEFS	2
SAVE$LOUT EQU	$+OFFSET
	DEFS	2
;
;Save the original SDVT here
DOSSDVT EQU	$+OFFSET
	DEFS	2
DOSCSTAT EQU	$+OFFSET
	DEFS	2
DOSCIND EQU	$+OFFSET
	DEFS	2
	DEFS	2
DOSCOUTD EQU	$+OFFSET
	DEFS	2
;
	ENDIF			;CDOS
ULCSW	EQU	$+OFFSET
	DEFS	1
;
OPTION	EQU	$+OFFSET
	DEFS	1
;
TOCNT	EQU	$+OFFSET
	DEFS	2
;
;Byte to keep track of lost carrier when
;typing "++CARRIER LOST++" so we don't loop
;
LOSTFLG EQU	$+OFFSET
	DEFS	1
;
;Save the CP/M jump table here
;
VCOLDBT EQU	$+OFFSET
	DEFS	3
;
VWARMBT EQU	$+OFFSET
	DEFS	3
;
VCONSTAT EQU	$+OFFSET
	DEFS	3
;
VCONIN	EQU	$+OFFSET
	DEFS	3
;
VCONOUT EQU	$+OFFSET
	DEFS	3
;
VLISTOUT EQU	$+OFFSET
	DEFS	3
;
;Since these areas are not initialized,
;the following counters will not be changed
;by subsequent loads of this program
;
	IF	USRLOG
OLDUSR	EQU	$+OFFSET
	DEFS	1
;
NEWUSR	EQU	$+OFFSET
	DEFS	1
;
NONUSR	EQU	$+OFFSET
	DEFS	1
	ENDIF			;USRLOG
;
;
	DEFS	60
STACK	EQU	$+OFFSET	;LOCAL STACK
;
ENDMARK EQU	$+OFFSET	IGNORE ERROR. THIS MARKS END OF PGM
;
;BDOS equates
;
CI	EQU	1
WRCON	EQU	2
DRECTIO EQU	6
PRINTF	EQU	9
CSTS	EQU	11
OPEN	EQU	15
READ	EQU	20
STDMA	EQU	26
BDOS	EQU	5
FCB	EQU	5CH 
FCBRNO	EQU	FCB+32
;
	END	
